package com.google.ant.extensions.tasks;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.google.ant.extensions.SourceRepo;
import com.google.ant.extensions.types.Dependencies;
import com.google.ant.extensions.types.Dependency;
import com.google.ant.extensions.types.DependencyHelper;
import com.google.ant.extensions.types.Module;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.taskdefs.Copy;
import org.apache.tools.ant.types.FilterSet.Filter;

public class JdeeTask extends AbstractFantTask {

    private Collection<Dependency> dependencies;
    private File basedir;
    private Collection<Module> depModules = new ArrayList<Module>();

    public void setDependencies(Collection<Dependency> dep) {
        this.dependencies = dep;
    }

    public void setBasedir(File dir) {
        this.basedir = dir;
    }

    public void execute() {
        basedir = getProject().getBaseDir();

        loadDep();

        Filter source = new Filter("source.path", getPath(getSourceDirs()));
        Filter classpath = new Filter("global.classpath", getPath(getGlobalClasspath()));

        Copy copy = new Copy();
        copy.createFilterSet().addFilter(source);
        copy.createFilterSet().addFilter(classpath);
        copy.setTodir(basedir);
        try {
            copy.setFile(new File(getFantBase(), "ide/jdee/prj.el"));
        } catch (Exception e) {
            throw new BuildException(e.getMessage());
        }

        copy.execute();
    }

    private String getFantBase() {
        String fantBase = System.getProperty("FANT_HOME");
        if (fantBase == null && getProject() != null) {
            fantBase = getProject().getProperty("ant.home") + "/etc/fant";
            System.setProperty("FANT_HOME", fantBase);
        }
        return fantBase;
    }

    private String getPath(List<String> path) {
        StringBuffer sb = new StringBuffer();
        for (String p : path) {
            sb.append("\"");
            sb.append(p);
            sb.append("\" ");
        }
        return sb.toString();
    }

    private void loadDep() {
        Dependencies dep = (Dependencies) getProject().getReference(Dependency.PRJ_DEP_NAME);
        if (dep != null) {
            dependencies = dep.getDependencies();
        } else {
            dependencies = new ArrayList<Dependency>();
        }
    }

    protected Collection<Module> getDependentModules() {
        if (depModules.isEmpty()) {
            Collection<Module> modules = new SourceRepo(getProject()).get();
            for (Dependency dependency : dependencies) {
                String sig = dependency.getSignature();
                for (Module module : modules) {
                    if (module.getSignature().equals(sig)) {
                        depModules.add(module);
                        break;
                    }
                }
            }
        }
        return depModules;
    }

    protected List<String> getSourceDirs() {
        List<String> results = new ArrayList<String>();
        for (Module module : getDependentModules()) {
            results.add(emitPath(module.getBasedir(), "/src/main/java"));
            results.add(emitPath(module.getBasedir(), "build/generated/src/main/java"));
            results.add(emitPath(module.getBasedir(), "src/test/java"));
        }
        results.add(emitPath(basedir.toString(), "src/main/java"));
        results.add(emitPath(basedir.toString(), "src/test/java"));
        results.add(emitPath(basedir.toString(), "build/generated/src/main/java"));
        return results;
    }

    protected List<String> getGlobalClasspath() {
        List<String> results = new ArrayList<String>();
        Collection<Dependency> globalDependencies = new DependencyHelper(getProject(),
                                                                         this.dependencies).getAllDependencies();
        for (Dependency dep : globalDependencies) {
            results.add(emitPath(basedir.toString(), "lib/" + dep.getArtifact()));
        }

        for (Module module : getDependentModules()) {
            results.add(emitPath(module.getBasedir(), "build/classes"));
            results.add(emitPath(module.getBasedir(), "build/test-classes"));
        }

        results.add(emitPath(basedir.toString(), "build/classes"));
        results.add(emitPath(basedir.toString(), "build/test-classes"));

        if (getProject() != null) {
            results.add(emitPath(getProject().getProperty("ant.extensions.dir"), "junit-4.3.1.jar"));
        }
        return results;
    }

    private String emitPath(String base, String path) {
        return new File(base, path).getAbsolutePath().toString().replace("\\", "/");
    }

}